package com.zyao89.view.zloading;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.element.Element;
import ohos.agp.render.Canvas;
import ohos.agp.render.ColorFilter;
import ohos.agp.utils.Color;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayAttributes;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;

import java.util.Optional;

/**
 * Created by zyao89 on 2017/3/19.
 * Contact me at 305161066@qq.com or zyao89@gmail.com
 * For more projects: https://github.com/zyao89
 * My Blog: http://zyao89.me
 */
public abstract class ZLoadingBuilder implements AnimatorValue.ValueUpdateListener, Animator.LoopedListener,
        Animator.StateChangedListener {
    /**
     * 外部可以修改，但是不建议
     */
    public static final float DEFAULT_SIZE = 65.0f;
    protected static final long ANIMATION_START_DELAY = 333;
    protected static final long ANIMATION_DURATION = 1333;
    private static final String TAG = "Zloading ZLoadingBuilder";

    private float mAllSize;
    private float mViewWidth;
    private float mViewHeight;

    private Element.OnChangeListener mCallback;
    private AnimatorValue mFloatValueAnimator;

    private double mDurationTimePercent = 1.0;

    void init(Context context) {
        mAllSize = dip2px(context, DEFAULT_SIZE * 0.5f - 12);
        mViewWidth = dip2px(context, DEFAULT_SIZE);
        mViewHeight = dip2px(context, DEFAULT_SIZE);
        initAnimators();
    }

    private void initAnimators() {
        mFloatValueAnimator = new AnimatorValue();
        mFloatValueAnimator.setLoopedCount(AnimatorProperty.INFINITE);
        mFloatValueAnimator.setDuration(getAnimationDuration());
        mFloatValueAnimator.setDelay(getAnimationStartDelay());
        mFloatValueAnimator.setCurveType(Animator.CurveType.LINEAR);
    }

    protected abstract void initParams(Context context, Color color);

    protected abstract void onDraw(Canvas canvas);

    protected abstract void setAlpha(int alpha);

    protected abstract void prepareStart(AnimatorValue animation);

    protected abstract void prepareEnd();

    protected abstract void computeUpdateValue(AnimatorValue animation, float animatedValue);

    protected abstract void setColorFilter(ColorFilter colorFilter);

    void setCallback(Element.OnChangeListener callback) {
        this.mCallback = callback;
    }

    void draw(Canvas canvas) {
        onDraw(canvas);
    }

    void start() {
        if (mFloatValueAnimator.isRunning()) {
            return;
        }
        mFloatValueAnimator.setValueUpdateListener(this);
        mFloatValueAnimator.setStateChangedListener(this);
        mFloatValueAnimator.setLoopedListener(this);
        mFloatValueAnimator.setLoopedCount(AnimatorProperty.INFINITE);
        mFloatValueAnimator.setDuration(getAnimationDuration());
        prepareStart(mFloatValueAnimator);
        mFloatValueAnimator.start();
    }

    void stop() {
        mFloatValueAnimator.setValueUpdateListener(null);
        mFloatValueAnimator.setLoopedListener(null);
        mFloatValueAnimator.setLoopedCount(0);
        mFloatValueAnimator.setDuration(0);
        prepareEnd();
        mFloatValueAnimator.end();
    }

    boolean isRunning() {
        return mFloatValueAnimator.isRunning();
    }

    @Override
    public void onUpdate(AnimatorValue animation, float v) {
        computeUpdateValue(animation, v);
        invalidateSelf();
    }

    private void invalidateSelf() {
        if (mCallback != null) {
            mCallback.onChange(null);
        }
    }

    @Override
    public void onStart(Animator animator) {

    }

    @Override
    public void onEnd(Animator animator) {

    }

    @Override
    public void onCancel(Animator animator) {

    }

    @Override
    public void onResume(Animator animator) {

    }

    @Override
    public void onStop(Animator animator) {

    }

    @Override
    public void onPause(Animator animator) {

    }

    public void setDurationTimePercent(double durationTimePercent) {
        if (durationTimePercent <= 0) {
            mDurationTimePercent = 1.0f;
        } else {
            mDurationTimePercent = durationTimePercent;
        }
    }

    protected long getAnimationStartDelay() {
        return ANIMATION_START_DELAY;
    }

    protected long getAnimationDuration() {
        return ceil(ANIMATION_DURATION * mDurationTimePercent);
    }

    protected float getIntrinsicHeight() {
        return mViewHeight;
    }

    protected float getIntrinsicWidth() {
        return mViewWidth;
    }

    protected final float getViewCenterX() {
        return getIntrinsicWidth() * 0.5f;
    }

    protected final float getViewCenterY() {
        return getIntrinsicHeight() * 0.5f;
    }

    protected final float getAllSize() {
        return mAllSize;
    }

    protected static float dip2px(Context context, float dpValue) {
        DisplayAttributes displayAttributes = getScreenPiex(context);
        return dpValue * displayAttributes.scalDensity;
    }

    public static DisplayAttributes getScreenPiex(Context context) {
        Optional<Display> display = DisplayManager.getInstance().getDefaultDisplay(context);
        DisplayAttributes displayAttributes = null;
        if (display.isPresent()) {
            displayAttributes = display.get().getAttributes();
        }
        return displayAttributes;
    }

    protected static long ceil(double value) {
        return (long) Math.ceil(value);
    }

}
